//=============================================================================
// XBus 
//-----------------------------------------------------------------------------
// File        : xbus_agent.c
// Description : 
// Author      : Ismail Sabry
// Date        : 1/30/2009
//=============================================================================
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <xbus_shm.h>
#include <xbus_module.h>
#include <xbus_cell.h>
#include <xbus_interface.h>

//-----------------------------------------------------------------------------
// 
//-----------------------------------------------------------------------------
int XBUS_link(t_XBUS_interface *interface, 
	      int type, char *xbus_name, int xbus_id)
{
  void           *addr;

  // check interface type
  if( (type != XBUS_CONSUMER) && (type != XBUS_FEEDER) ) {
    printf("XBus : unsupported interface tye (%d)\n", type);
    return -1;
  }

  // init interface
  memset(interface, 0,sizeof(t_XBUS_interface));

  snprintf(interface->name, XBUS_SIZE_NAME-1, "%s", xbus_name);
  interface->id   = xbus_id;
  interface->type = type;

  XBUS_link_shm(interface->name, &addr);
  interface->xbus = (t_XBUS *)addr;

  // check XBUS magic
  if(interface->xbus->head.magictag != XBUS_MAGICTAG_XBUS) {
    printf("XBUS bad Magic %X \n", (int)interface->xbus->head.magictag);
    return -1;
  }

  // check xbus_id (index module)
  if( (interface->id < 0) || (interface->id >= interface->xbus->head.nb_module) ) {
    printf("XBus : bad id %d [0 ... %d]\n", interface->id, interface->xbus->head.nb_module-1);
    XBUS_unlink_shm(interface->name, (void *)interface->xbus);
    return -1 ;
  }

  // link module
  interface->module = XBUS_get_module_by_index(interface->xbus, interface->id);
  // check modeul magic
  if(interface->module->head.magictag != XBUS_MAGICTAG_MODULE) {
    printf("XBUS bad Module %X \n", (int)interface->module->head.magictag);
    XBUS_unlink_shm(interface->name, (void *)interface->xbus);
    return -1 ;
  }

  // init first
  interface->first = &interface->module->cell;

  // check first cell magic
  if(interface->first->head.magictag != XBUS_MAGICTAG_CELL) {
    printf("XBUS bad First %X \n", (int)interface->first->head.magictag);
    XBUS_unlink_shm(interface->name, (void *)interface->xbus);
    return -1 ;
  }
  
  // synho sur iwrite (feeder & consumer)
  interface->cell = XBUS_get_cell_by_index(interface->xbus,
					   interface->module, 
					   interface->module->head.wcell);
  if(interface->cell == (t_XBUS_cell *)-1) {
    printf("XBUS invalid cell %d \n", interface->module->head.wcell);
    XBUS_unlink_shm(interface->name, (void *)interface->xbus);
    return -1 ;    
  }

  // check cell magic
  if(interface->cell->head.magictag != XBUS_MAGICTAG_CELL) {
    printf("XBUS bad Cell %X \n", (int)interface->cell->head.magictag);
    XBUS_unlink_shm(interface->name, (void *)interface->xbus);
    return -1 ;
  }
  
  if(type == XBUS_FEEDER) {
    XBUS_init_module(interface->module);
  }

  interface->riter = interface->module->head.witer;
  interface->rcell  = interface->module->head.wcell;
  
  return 0 ;
}

//-----------------------------------------------------------------------------
// 
//-----------------------------------------------------------------------------
int XBUS_unlink(t_XBUS_interface *interface)
{
  XBUS_unlink_shm(interface->name, (void *)interface->xbus);
  return(0);
}

//-----------------------------------------------------------------------------
// 
//-----------------------------------------------------------------------------
int XBUS_write(t_XBUS_interface *interface, unsigned char *buf, unsigned int len)
{
  int             ret;
  
  if(XBUS_lock(interface->module, 0) != -1) {
    
    ret = XBUS_write_cell(interface->xbus, interface->cell, buf, len);
    
    // next cell
    interface->cell = XBUS_get_next_cell(interface->cell);
    

    if( interface->cell == interface->first ) {
      interface->module->head.wcell = 0;
      interface->module->head.witer += 1;
    } else {
      interface->module->head.wcell += 1;
    }

    XBUS_unlock(interface->module);

  } else {
    printf("XBUS lock timeout (module %d)\n", interface->id);
    ret = -1;
  }
  
  return(ret);
}


//-----------------------------------------------------------------------------
// 
//-----------------------------------------------------------------------------
int XBUS_read(t_XBUS_interface *interface, unsigned char *buf, unsigned int len)
{
  int                   ret;
  t_XBUS_module_header  *module;

  module = &interface->module->head;
  
  if(XBUS_lock(interface->module, 0) != -1) {
    
    // no data to read
    if( (module->witer == interface->riter ) && (module->wcell == interface->rcell) ) {
      ret = 0;
    }
    else {
      // valid data
      if( ( (module->witer == (interface->riter))  /* && (module->wcell > interface->rcell)*/ ) ||
	  ( (module->witer == (interface->riter+1)) && (module->wcell < interface->rcell) ) ) {
      
	ret = XBUS_read_cell(interface->xbus, interface->cell, buf, len);
      
      //  printf("module->witer %d interface->riter %d module->wcell %d interface->rcell %d \n",module->witer,interface->riter,module->wcell,interface->rcell);
	// next cell
	interface->cell = XBUS_get_next_cell(interface->cell);
	
	if( interface->cell == interface->first ) {
	  interface->rcell = 0;
	  interface->riter += 1;
	} else {
	  interface->rcell += 1;
	}
	
      } else {
	// resynch (=> perte de donnée)
	printf("XBUS resynch (%s) (module %d)\n", interface->name,interface->id);
	interface->riter = module->witer;
       // printf("ER module->witer %d interface->riter %d module->wcell %d interface->rcell %d \n",module->witer,interface->riter,module->wcell,interface->rcell);
	interface->rcell = module->wcell;
	ret = 0;
      }
    }
    
    XBUS_unlock(interface->module);
    
  } else {
    printf("XBUS lock timeout (module %d)\n", interface->id);
    ret = -1;
  }
 //if(ret > 0)
  return(ret);
}
